#ifndef _COMDEFINE_H
#define _COMDEFINE_H

//#define  OS_LINUX


#include <assert.h>
#include <iostream>
#include <string.h>
#include "utility.h"
#include "base/core/os/debug.h"
#include "base/core/log.h"

#if defined(_MSC_VER)
  #define  _UNUSE(PARAM)   PARAM
#elif defined(OS_LINUX)
  #define  _UNUSE(PARAM)
#endif  // OS

#if defined(_MSC_VER)
#define  MMO_USE_ARGUMENT(arg)   arg
#elif defined(OS_LINUX)
#define  MMO_USE_ARGUMENT(arg)
#endif  // OS

#if defined(_MSC_VER)
#define DO_WHILE_MACRO_BEGIN do {
#define DO_WHILE_MACRO_END(VALUE)       \
  __pragma(warning(push))               \
  __pragma(warning(disable:4127))       \
} while (VALUE)                         \
  __pragma(warning(pop))
#elif defined(OS_LINUX)
#define DO_WHILE_MACRO_BEGIN      do {
#define DO_WHILE_MACRO_END(VALUE) } while (VALUE)
#endif  // OS

// TODO: contorl by make command
#define MMO_ENABLE_ASSERT

#ifdef MMO_ENABLE_ASSERT
#define MMO_ASSERT(a) assert(a)
#else
#define MMO_ASSERT(a)
#endif

#define MMO_RETURN_SYSERR(r, e)          \
  DO_WHILE_MACRO_BEGIN                  \
  SetErrorNO(e);                        \
  return (r);                           \
  DO_WHILE_MACRO_END(false)

// set e as errno and return r if !a
#define MMO_ASSERT_ERROR(a, r, e)        \
  DO_WHILE_MACRO_BEGIN                  \
  auto macroRet = (a);                  \
  MMO_ASSERT((#a) && (macroRet));         \
  if (!macroRet) {                      \
    MMO_RETURN_SYSERR(r, e);             \
  }                                     \
  DO_WHILE_MACRO_END(false)

#define MMO_ASSERT_EXIT(condition)       \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        MMO_ASSERT((#condition) && macroRet);  \
        if (!macroRet)                  \
            goto Exit0;                 \
  DO_WHILE_MACRO_END(false)

#define MMO_PROCESS_ERROR(condition)     \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet)                  \
            goto Exit0;                 \
  DO_WHILE_MACRO_END(false)

#define MMO_PROCESS_SUCCESS(condition)   \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (macroRet)                   \
            goto Exit1;                 \
  DO_WHILE_MACRO_END(false)

#define MMO_PROCESS_FALSE(condition)     \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (macroRet)                   \
            goto Exit0;                 \
  DO_WHILE_MACRO_END(false)

#define MMO_PROCESS_ERROR_RET_CODE(condition, Code) \
  DO_WHILE_MACRO_BEGIN                             \
        auto macroRet = (condition);               \
        if (!macroRet) {                           \
            nResult = Code;                        \
            goto Exit0;                            \
        }                                          \
  DO_WHILE_MACRO_END(false)

#define MMO_COM_RELEASE(pInterface)      \
  DO_WHILE_MACRO_BEGIN                  \
        if (pInterface) {               \
            (pInterface)->Release();    \
            (pInterface) = NULL;        \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMO_DELETE_ARRAY(pArray)         \
  DO_WHILE_MACRO_BEGIN                  \
        if (pArray) {                   \
            delete[](pArray);           \
            (pArray) = NULL;            \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMO_DELETE(p)                    \
  DO_WHILE_MACRO_BEGIN                  \
        if (p) {                        \
            delete (p);                 \
            (p) = NULL;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

inline const char * LogFileNameAndFunction(const char *fileName) {
    int len = (int)strlen(fileName);
    int cnt = 0;
    for (int i = len - 1; i >= 0; --i) {
        if (fileName[i] == '\\' || fileName[i] == '/') {
            if (++cnt == 3) return fileName + i + 1;
        }
    }
    return fileName;
}

#define MMOLOG_ASSERT(condition)         \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {              \
            WriteFormatLog(             \
                LOG_PRIORITY_DEBUG,     \
                "MMOLOG_ASSERT(%s) at File %s(%d) Function %s", #condition,    \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__ \
            );                          \
            MMO_ASSERT((#condition) && macroRet);  \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_ASSERT_EXIT(condition)    \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_ERR,     \
                "MMOLOG_ASSERT_EXIT(%s) at File %s(%d) Function %s", #condition,    \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__ \
            );                          \
            MMO_ASSERT((#condition) && macroRet);  \
            goto Exit0;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_ASSERT_RET(condition, ret)    \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_DEBUG,     \
                "MMOLOG_ASSERT_RET(%s, %s) at File %s(%d) Function %s", #condition, #ret,    \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__ \
            );                          \
            MMO_ASSERT((#condition) && macroRet);  \
            return ret;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_PROCESS_ERRLOG(condition) \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_ERRLOG,       \
                "MMOLOG_PROCESS_WARN(%s) at File %s(%d) Function %s", #condition,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                          \
            goto Exit0;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_PROCESS_WARN(condition) \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_WARNING,    \
                "MMOLOG_PROCESS_WARN(%s) at File %s(%d) Function %s", #condition,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                          \
            goto Exit0;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_PROCESS_ERROR(condition) \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_ERR,       \
                "MMOLOG_PROCESS_ERROR(%s) at File %s(%d) Function %s", #condition,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                          \
            goto Exit0;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_PROCESS_ERROR_INFO(condition, strInfo)  \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_ERR,     \
                "MMOLOG_PROCESS_ERROR_INFO(%s, %s) at File %s(%d) Function %s", #condition, strInfo,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                          \
            goto Exit0;                 \
        }                               \
  DO_WHILE_MACRO_END(false)


#define MMOLOG_PROCESS_ERROR_INFO(condition, strInfo)  \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_ERR,     \
                "MMOLOG_PROCESS_ERROR_INFO(%s, %s) at File %s(%d) Function %s", #condition, strInfo,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                          \
            goto Exit0;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_PROCESS_ERROR_RET(condition, ret)  \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_ERR,     \
                "MMOLOG_PROCESS_ERROR_RET(%s, %s) at File %s(%d) Function %s", #condition, #ret,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                          \
            return ret;                 \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_PROCESS_ERROR_RET_CODE(condition, ErrorCode)  \
    DO_WHILE_MACRO_BEGIN                \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_ERR,     \
                "MMOLOG_PROCESS_ERROR_CODE(%s) at File %s(%d) Function %s", #condition, \
                LogFileNameAndFunction(__FILE__), __LINE__, __FUNCTION__  \
            );                          \
            nResult = ErrorCode;         \
            goto Exit0;                 \
        }                               \
    DO_WHILE_MACRO_END(false)

#define MMOLOG_OUTPUT_ERROR(condition)   \
  DO_WHILE_MACRO_BEGIN                  \
        auto macroRet = (condition);    \
        if (!macroRet) {                \
            WriteFormatLog(             \
                LOG_PRIORITY_DEBUG,     \
                "MMOLOG_OUTPUT_ERROR(%s) at File %s(%d) Function %s", #condition,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                          \
        }                               \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_PROCESS_SUCCESS(condition) \
  DO_WHILE_MACRO_BEGIN                   \
        auto macroRet = (condition);     \
        if (macroRet) {                  \
            WriteFormatLog(              \
                LOG_PRIORITY_DEBUG,      \
                "MMOLOG_PROCESS_SUCCESS(%s) at File %s(%d) Function %s", #condition, \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );                           \
            goto Exit1;                  \
        }                                \
  DO_WHILE_MACRO_END(false)

#define MMOLOG_FMT_DEBUG(format, ...) \
            WriteFormatLog(             \
                LOG_PRIORITY_DEBUG,     \
                "MMOLOG_FMT_DEBUG(" #format ") at File %s(%d) Function %s", ##__VA_ARGS__,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );   

#define MMOLOG_FMT_WARN(format, ...)   \
            WriteFormatLog(              \
                LOG_PRIORITY_WARNING,    \
                "MMOLOG_FMT_WARN(" #format ") at File %s(%d) Function %s", ##__VA_ARGS__,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            ); 

#define MMOLOG_FMT_INFO(format, ...)   \
            WriteFormatLog(              \
                LOG_PRIORITY_INFO,    \
                "MMOLOG_FMT_INFO(" #format ") at File %s(%d) Function %s", ##__VA_ARGS__,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            );

#define MMOLOG_FMT_ERROR(format, ...)   \
            WriteFormatLog(              \
                LOG_PRIORITY_ERR,    \
                "MMOLOG_FMT_ERROR(" #format ") at File %s(%d) Function %s", ##__VA_ARGS__,  \
                LogFileNameAndFunction(__FILE__), __LINE__,  __FUNCTION__  \
            ); 

#define MMO_Print(stream)    std::cout << stream
#define MMO_Printl(stream)   std::cout << stream << std::endl
#define MMO_ERROR(stream)    {MMO_ASSERT(false);std::cout << "[Error] " << __FUNCTION__ << '(' << __LINE__ << ") " << stream << std::endl;}
#define MMO_INFO(stream)     {std::cout << "[Info] " << __FUNCTION__ << '(' << __LINE__ << ") " << stream << std::endl;}

//#define MMO_CONFIRM_RET(condition, ret)  if (!(condition)) {MMO_ERROR(""); return ret;}
#define MMO_CONFIRM_RET_FALSE(condition) if (!(condition)) {MMO_ERROR(""); return false;}
#define MMO_CONFIRM_RET_NULL(condition)  if (!(condition)) {MMO_ERROR(""); return 0;}
#define MMO_CONFIRM_BREAK(condition)     if (!(condition)) {MMO_ERROR(""); break;}
#define MMO_CONFIRM_RET_VOID(condition)  if (!(condition)) {MMO_ERROR(""); return;}
#define MMO_CONFIRM_CONTINUE(condition)  if (!(condition)) {MMO_ERROR(""); continue;}

#define MMO_INFO_RET(condition, ret)     if (!(condition)) {MMO_INFO(""); return ret;}
#define MMO_INFO_RET_FALSE(condition)    if (!(condition)) {MMO_INFO(""); return false;}
#define MMO_INFO_RET_NULL(condition)     if (!(condition)) {MMO_INFO(""); return 0;}
#define MMO_INFO_BREAK(condition)        if (!(condition)) {MMO_INFO(""); break;}
#define MMO_INFO_RET_VOID(condition)     if (!(condition)) {MMO_INFO(""); return;}
#define MMO_INFO_CONTINUE(condition)     if (!(condition)) {MMO_INFO(""); continue;}

#define MMO_RET(condition, ret)          if (!(condition)) {return ret;}
#define MMO_RET_FALSE(condition)         if (!(condition)) {return false;}
#define MMO_RET_NULL(condition)          if (!(condition)) {return 0;}
#define MMO_BREAK(condition)             if (!(condition)) {break;}
#define MMO_RET_VOID(condition)          if (!(condition)) {return;}
#define MMO_CONTINUE(condition)          if (!(condition)) {continue;}

#if defined(WIN32)
#define LIKELY(x)       (x)
#define UNLIKELY(x)     (x)
#elif defined(OS_LINUX)
#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
#define __builtin_expect(x, expected_value) (x)
#endif
#define LIKELY(x)       __builtin_expect((x), 1)
#define UNLIKELY(x)     __builtin_expect((x), 0)
#endif

#if defined(WIN32)
#define MMO_LIKELY(x)       (x)
#define MMO_UNLIKELY(x)     (x)
#elif defined(OS_LINUX)
#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
#define __builtin_expect(x, expected_value) (x)
#endif
#define MMO_LIKELY(x)       __builtin_expect((x), 1)
#define MMO_UNLIKELY(x)     __builtin_expect((x), 0)
#endif

#ifdef WIN32
#define MMO_PATH_SEPRATOR '\\'
#else
#define MMO_PATH_SEPRATOR '/'
#endif

#ifndef countof
#define countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#endif


#define MMO_LOWORD(l)           ((uint16_t)(l))
#define MMO_HIWORD(l)           ((uint16_t)(((uint32_t)(l) >> 16) & 0xFFFF))
#define MMO_LOBYTE(w)           ((uint8_t)(w))
#define MMO_HIBYTE(w)           ((uint8_t)(((uint16_t)(w) >> 8) & 0xFF))
#define MMO_LOWLONG(ll)         ((uint32_t)(ll))
#define MMO_HILONG(ll)           (uint32_t)(((uint64_t)(ll) >> 32) & 0xFFFFFFFF)
#define MMO_MAKEWORD(a, b)      ((uint16_t)(((uint8_t)(a))  | ((uint16_t)((uint8_t)(b))) << 8))
#define MMO_MAKELONG(a, b)      ((uint32_t)(((uint16_t)(a)) | ((uint32_t)((uint16_t)(b))) << 16))
#define MMO_MAKELONGLONG(a, b)  ((uint64_t)(((uint32_t)(a)) | ((uint64_t)((uint32_t)(b))) << 32))


#endif   //_COMDEFINE_H